/****************************************
 * Copyright (c) 2015 NiuWa.
 * All rights reserved.
 * Created on 2015年4月15日
 * 
 * Contributors:
 * 	   Percy.Lo - initial implementation
 ****************************************/
package com.niuwa.p2p.server.manggoDB;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;
import com.mongodb.WriteResult;

/**
 * 
 * @title 基于manggoDB的数据库操作
 *
 * @author Percy.Lo
 * @version 1.0
 * @created 2015年4月24日
 */
public class MongoDBManager {

	public DB db;
	private static final Integer SOTIMEOUT = 300000;
	private static final Integer CONNECTIONSPERHOST = 500;
	private static final Integer THREADSALLOWEDTOBLOCKFORCONNECTIONMULTIPLIER = 500;

	public MongoDBManager(String host, int port, String database) throws Exception {
		MongoClient mongoClient = new MongoClient(new ServerAddress(host, port), new MongoClientOptions.Builder().socketTimeout(SOTIMEOUT).connectionsPerHost(CONNECTIONSPERHOST).threadsAllowedToBlockForConnectionMultiplier(THREADSALLOWEDTOBLOCKFORCONNECTIONMULTIPLIER).socketKeepAlive(true).build());
		db = mongoClient.getDB(database);
	}
	public WriteResult insert(String collection, List<DBObject> list) throws Exception {
		return db.getCollection(collection).insert(list,WriteConcern.SAFE);
	}
	public WriteResult insert(String collection, DBObject dbObject) throws Exception {
		return db.getCollection(collection).insert(dbObject,WriteConcern.SAFE);
	}
	public WriteResult save(String collection, DBObject dbObject) throws Exception {
		return db.getCollection(collection).save(dbObject,WriteConcern.SAFE);
	}

	public WriteResult delete(String collection, DBObject query) throws Exception {
		return db.getCollection(collection).remove(query,WriteConcern.SAFE);
	}

	// 此处不使用toArray()方法直接转换为List,是因为toArray()会把结果集直接存放在内存中，
	// 如果查询的结果集很大，并且在查询过程中某一条记录被修改了，就不能够反应到结果集中，从而造成"不可重复读"
	// 而游标是惰性获取数据
	public List<DBObject> find(String collection, DBObject query, DBObject fields, int limit) {
		List<DBObject> list = new LinkedList<>();
		DBCursor cursor = db.getCollection(collection).find(query, fields).limit(limit);
		while (cursor.hasNext()) {
			list.add(cursor.next());
		}
		return list.size() > 0 ? list : null;
	}

	public List<DBObject> find(String collection, DBObject query, DBObject fields, DBObject orderBy, int pageNum, int pageSize) {
		List<DBObject> list = new ArrayList<>();
		DBCursor cursor = db.getCollection(collection).find(query, fields).skip((pageNum - 1) * pageSize).limit(pageSize).sort(orderBy);
		while (cursor.hasNext()) {
			list.add(cursor.next());
		}
		return list.size() > 0 ? list : null;
	}

	public DBObject findOne(String collection, DBObject query, DBObject fields) {
		return db.getCollection(collection).findOne(query, fields);
	}

	public DBObject findAndModify(String collection, DBObject query, DBObject fields) {
		return db.getCollection(collection).findAndModify(query,new BasicDBObject("$set",fields));
	}

	
	public WriteResult update(String collection, DBObject query, DBObject update, boolean upsert, boolean multi) throws Exception {
		return db.getCollection(collection).update(query, update, upsert, multi,WriteConcern.SAFE);
	}

	public long count(String collection, DBObject query) {
		return db.getCollection(collection).count(query);
	}

	// 查询出key字段,去除重复，返回值是{_id:value}形式的list
	@SuppressWarnings("rawtypes")
	public List distinct(String collection, String key, DBObject query) {
		return db.getCollection(collection).distinct(key, query);
	}

}
